﻿using System;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using Av.Utils;
using System.Text;
using System.Net;
using System.Collections.Specialized;

namespace JrGreenMonster
{
    public partial class Form1 : Form
    {

        /// <summary>
        /// Systray icon
        /// </summary>
        protected NotifyIcon m_icon = null;

        protected IttcWorkerThread m_workerThread = null;

        #region " Get/set text methods (invoked) "

        delegate void SetTextDelegate(string name, string value);
        delegate string GetTextDelegate(string name);

        /// <summary>
        /// Returns text of control.
        /// </summary>
        /// <param name="name">Name of control</param>
        /// <returns>Text of control. Returns "checked"/"" or "" for CheckBox</returns>
        private string GetText(string name)
        {
            string s = "";

            try
            {
                if(this.InvokeRequired)
                {
                    this.Invoke(new GetTextDelegate(GetText), name);
                } else
                {
                    Control[] ar = this.Controls.Find(name, false);
                    if((ar != null) && (ar.Length > 0))
                    {
                        if(ar[0].GetType() == typeof(CheckBox))
                        {
                            s = ((CheckBox)ar[0]).Checked ? "checked" : "";
                        } else
                        {
                            s = ar[0].Text;
                        }
                    }
                }
            } catch(Exception ex)
            {
            }

            return s;
        }

        /// <summary>
        /// Thread safe AddText
        /// </summary>
        /// <param name="name">Name of control to add text</param>
        /// <param name="value">Text to add</param>
        private void AddText(string name, string value)
        {
            try
            {
                if(this.InvokeRequired)
                {
                    this.Invoke(new SetTextDelegate(AddText), name, value);
                } else
                {
                    Control[] ar = this.Controls.Find(name, false);
                    if((ar != null) && (ar.Length > 0))
                    {
                        ar[0].Text += value;
                        if(ar[0].GetType() == typeof(TextBox))
                        {
                            ((TextBox)ar[0]).SelectionStart = Int32.MaxValue;
                        }
                    }
                }
            } catch(Exception)
            {
            }
        }

        /// <summary>
        /// Thread safe SetText
        /// </summary>
        /// <param name="name">Name of control to set text</param>
        /// <param name="value">Text to set</param>
        private void SetText(string name, string value)
        {
            try
            {
                if(this.InvokeRequired)
                {
                    this.Invoke(new SetTextDelegate(SetText), name, value);
                } else
                {
                    Control[] ar = this.Controls.Find(name, false);
                    if((ar != null) && (ar.Length > 0))
                    {
                        ar[0].Text = value;
                    }
                }

            } catch(Exception ex)
            {
            }
        }

        #endregion

        public Form1()
        {
            InitializeComponent();
        }

        private void OnFormClosed(object sender, FormClosedEventArgs e)
        {
            if(m_icon != null)
            {
                m_icon.Dispose();
            }

            if( m_thread != null )
            {
                Log4cs.Log(Importance.Warning, "Killing upload thread!");
                m_thread.Join(200);
                m_thread.Abort();
            }

            if( m_workerThread != null )
            {
                Log4cs.Log("Stopping ITTC worker thread");
                m_workerThread.Stop();
            }
        }

        private void OnFormLoad(object sender, EventArgs e)
        {
            try
            {
                Log4cs.Log("Starting {0} (v{1})...", Settings.Name, Settings.Version);
                Debug("Starting {0}...", Settings.NameVersion);

                // In case we need only one instance of program
                EnsureSingleApplication();

                this.Text = Settings.NameVersion;

                // Creates icons using emebedded icon
                CreateFormIcons();

                // Create context menu for tray icon
                MenuItem[] arMenu = this.CreateMenuItems();
                if(arMenu != null)
                {
                    m_icon.ContextMenu = new ContextMenu(arMenu);
                }

                lstFrequency.Items.AddRange(new string[] { "1", "2", "5", "10", "15", "25", "40", "60", "90", "120" });
                lstFrequency.SelectedIndex = lstFrequency.Items.Count - 1;

                txtServerAddress.Text = string.Format("{0}:{1}/", Settings.IttcHostname, Settings.IttcPort);

                // Prepare ITTC worker thread
                m_workerThread = new IttcWorkerThread();
                m_workerThread.StatusChanged += new MyNotificationDelegate(OnWorkerThreadStatusChanged);

                // Hides application (form) if necessary
                //HideApplication();

            } catch(ApplicationException ex)
            {
                Debug(Importance.Error, "Application already run, check logs!");
                MessageBox.Show(ex.ToString(), string.Format("{0} (v{1})", Settings.Name, Settings.Version), MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Close();
            } catch(Exception ex)
            {
                Log4cs.Log(Importance.Error, "Error loading main form!");
                Log4cs.Log(Importance.Debug, ex.ToString());
                MessageBox.Show("Error loading application!", string.Format("{0} (v{1})", Settings.Name, Settings.Version), MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Close();
            }
        }

        void OnWorkerThreadStatusChanged(object sender, MyNotificationEventArgs args)
        {
            Debug(args.Text);
        }

        /// <summary>
        /// Hides application (form) and from taskbar
        /// </summary>
        protected void HideApplication()
        {
            this.ShowInTaskbar = false;
            this.Visible = false;
        }

        /// <summary>
        /// Hides from Alt-TAB
        /// </summary>
        //protected override CreateParams CreateParams
        //{
        //    get
        //    {
        //        CreateParams cp = base.CreateParams;

        //        // Turns on WS_EX_TOOLWINDOW style bit to hide from Alt-TAB list
        //        cp.ExStyle |= 0x80;

        //        return cp;
        //    }
        //}

        /// <summary>
        /// Creates tray icon from embedded to project icon. Throws execptions
        /// </summary>
        private void CreateFormIcons()
        {
            // Create tray icon
            Assembly asm = Assembly.GetExecutingAssembly();
            FileInfo fi = new FileInfo(asm.GetName().Name);
            using(Stream s = asm.GetManifestResourceStream(string.Format("{0}.av1.ico", fi.Name)))
            {
                // Create icon to be used in Form and Tray
                Icon icon = new Icon(s);

                Icon = new Icon(icon, icon.Size);

                m_icon = new NotifyIcon();
                m_icon.Visible = true;
                m_icon.Icon = new Icon(icon, icon.Size);

                icon.Dispose();
            }
        }

        /// <summary>
        /// Ensures that application is the only. Throws ApplicationException if there is such application
        /// </summary>
        private void EnsureSingleApplication()
        {
            bool createdNew = false;
            Mutex mx = new Mutex(false, Settings.Name, out createdNew);
            Log4cs.Log(Importance.Debug, "Is mutex created: {0}", createdNew);

            // If application is already running
            if(createdNew == false)
            {
                throw new ApplicationException(Settings.Name + " application is already running!");
            }
        }


        #region " Debug to UI console "

        /// <summary>
        /// Outputs message to UI output console
        /// </summary>
        /// <param name="msg">Message to input, could be used like string.Format()</param>
        /// <param name="args"></param>
        protected void Debug(string msg, params object[] args)
        {
            Debug(Importance.Info, msg, args);
        }

        /// <summary>
        /// Outputs message to UI output console
        /// </summary>
        /// <param name="level">Level of imortance - Error, Info, etc...</param>
        /// <param name="msg">Message to input, could be used like string.Format()</param>
        /// <param name="args"></param>
        protected void Debug(Importance level, string msg, params object[] args)
        {
            StringBuilder sb = new StringBuilder();
            if(level != Importance.No)
            {
                sb.AppendFormat("[{0}] ", level.ToString().ToUpper());
            }

            sb.AppendFormat(msg, args);
            sb.AppendLine();
            this.AddText("txtOutput", sb.ToString());
            txtOutput.SelectionStart = int.MaxValue;
            txtOutput.ScrollToCaret();
        }

        #endregion


        #region " Context menu methods "

        /// <summary>
        /// Creates context menu for tray icon
        /// </summary>
        /// <returns></returns>
        private MenuItem[] CreateMenuItems()
        {
            MenuItem[] arMenu = null;

            try
            {
                // Got quantity of menus
                arMenu = new MenuItem[MyMenu.Size];

                for(int i = 0; i < MyMenu.Size; i++)
                {
                    arMenu[i] = new MenuItem(MyMenu.ToName(i), OnContextMenuClicked);
                }

                // By default status thread is stopped, so disable "Stop" command
                arMenu[MyMenu.Position.Stop].Enabled = false;

                // Format "Version"
                arMenu[MyMenu.Position.Version].Text = string.Format("{0} (v{1})", Settings.Name, Settings.Version);

            } catch(Exception ex)
            {
                Log4cs.Log(Importance.Error, "Error creating menu items!");
                Log4cs.Log(Importance.Debug, ex.ToString());
            }

            return arMenu;
        }

        /// <summary>
        /// Handles clicks on systray icon menu
        /// </summary>
        void OnContextMenuClicked(object sender, EventArgs e)
        {
            try
            {
                switch(((MenuItem)sender).Index)
                {
                    case MyMenu.Position.Start:
                        //m_icon.ContextMenu.MenuItems[MyMenu.Position.Start].Enabled = false;
                        //m_icon.ContextMenu.MenuItems[MyMenu.Position.Stop].Enabled = true;
                        OnStartStopClicked(null, null);
                        break;
                    case MyMenu.Position.Stop:
                        //m_icon.ContextMenu.MenuItems[MyMenu.Position.Start].Enabled = true;
                        //m_icon.ContextMenu.MenuItems[MyMenu.Position.Stop].Enabled = false;
                        OnStartStopClicked(null, null);
                        break;
                    case MyMenu.Position.Version:
                        MessageBox.Show("Simple JRC green monster by mr. Aleksej Vasinov", Settings.NameVersion, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        break;
                    //case MyMenu.Position.Reload:
                    //    ReloadSettings();
                    //    break;
                    default:
                        this.Close();
                        break;
                }

            } catch(Exception ex)
            {
                Log4cs.Log(Importance.Error, "Error handling context menu click!");
                Log4cs.Log(Importance.Debug, ex.ToString());
            }
        }


        /// <summary>
        /// Reloads setting. Stops thread if necessary
        /// </summary>
        private void ReloadSettings()
        {
            Log4cs.Log("Reloading settings...");
            Settings.Load();
        }

        /// <summary>
        /// Starts/stops application if needed :)
        /// </summary>
        private void OnStartStopClicked(object sender, EventArgs e)
        {
            Log4cs.Log("Start/stop is clicked. Is ITTC thread running - {0}...", m_workerThread.IsRunning);

            // Thread is stopped, make it run
            if(!m_workerThread.IsRunning)
            {
                StartWorkerThread();
            } else
            {
                m_workerThread.Stop();
            }
            //m_workerThread.IsRunning = !m_workerThread.IsRunning;

            UpdateStarStop();
        }

        #endregion

        private void OnTestButtonClicked(object sender, EventArgs e)
        {
            Debug("Min delay is: {0}", new TimeDelayWatcher().GetSecondsTillFirstRun());
            //if(m_thread == null)
            //{
            //    m_thread = new Thread(new ParameterizedThreadStart(UploadFileThread));
            //    m_thread.Start();
            //} else
            //{
            //    Debug("File is uploading...");
            //}
        }

        /// <summary>
        /// Parses
        /// </summary>
        protected void StartWorkerThread()
        {
            int delayM = 0;
            if(!int.TryParse(lstFrequency.SelectedItem.ToString(), out delayM))
            {
                delayM = 60;
            }

            IttcWorkerConfiguration config = new IttcWorkerConfiguration()
            {
                CstSignalsUploadDelayS = delayM * 60
                ,
                IttcUrl = txtServerAddress.Text
                ,
                CstSignalsUploadUrl = string.Format("{0}{1}test/uploadsignals/3/", txtServerAddress.Text, txtServerAddress.Text.EndsWith("/") ? "" : "/")
                ,
                CstSignalsFilename = txtFileToSend.Text
            };

            if(!File.Exists(config.CstSignalsFilename))
            {
                Log4cs.Log("CST signals file [{0}] does not exist!", config.CstSignalsFilename);
                Debug("CST signals file [{0}] does not exist!", config.CstSignalsFilename);
                return;
            }

            m_workerThread.Start(config);
        }

        /// <summary>
        /// Updates context menu and worker start/stop button according to ITTC thread state
        /// </summary>
        private void UpdateStarStop()
        {
            m_icon.ContextMenu.MenuItems[MyMenu.Position.Start].Enabled = !m_workerThread.IsRunning;
            m_icon.ContextMenu.MenuItems[MyMenu.Position.Stop].Enabled = m_workerThread.IsRunning;
            btnStartStop.Text = m_workerThread.IsRunning ? "Stop" : "Start";
        }

        protected Thread m_thread = null;
        protected void UploadFileThread(object obj)
        {
            try
            {
                string resp = "";
                byte[] ba = null;
                string csrfToken = "";
                string filename = txtFileToSend.Text;
                //string urlToSend = string.Format("{0}:{1}/test/uploadsignals/3/", Settings.IttcHostname, Settings.IttcPort);
                //string urlToSend = string.Format("{0}/test/uploadsignals/3/", txtServerAddress.Text);
                //Debug("Trying to upload file {0} to ITTC server {1}...", filename, urlToSend);

                //IttcWebClient wc = new IttcWebClient();
                //resp = wc.PostCstSignals(urlToSend, filename);
                //Debug("Got response from ITTC server: {0}", resp);
            }catch(ThreadInterruptedException)
            {
                Log4cs.Log("Thread was interrupted, finishing it!");
            } catch(Exception ex)
            {
                Log4cs.Log(Importance.Error, "Error uploading file to ITTC server!");
                Log4cs.Log(Importance.Debug, ex.ToString());
                Debug(Importance.Error, "Error uploading file to ITTC server!");
            }

            m_thread = null;
        }

        private void OnFileToSendMouseClicked(object sender, MouseEventArgs e)
        {
            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                dlg.Filter = "Text files|*.txt|All files|*.*";
                if( dlg.ShowDialog() == DialogResult.OK )
                {
                    txtFileToSend.Text = dlg.FileName;
                }
            } catch(Exception ex)
            {
                Log4cs.Log(Importance.Error, "Error opening file dialog!");
                Log4cs.Log(Importance.Debug, ex.ToString());
                Debug(Importance.Error, "Error opening file dialog!");
            }
        }

        /// <summary>
        /// Switch file watcher work. Stops ITTC worker thread if needed
        /// </summary>
        private void OnFileWatcherChanged(object sender, EventArgs e)
        {
            bool isChecked = ((CheckBox)sender).Checked;
            if(isChecked)
            {
                // Stop ITTC thread and disable its control, everything will be done from FileWatcher
                m_workerThread.Stop();
                lstFrequency.Enabled = false;
                btnStartStop.Enabled = false;
            } else
            {
                lstFrequency.Enabled = true;
                btnStartStop.Enabled = true;
            }

            UpdateStarStop();
        }

    }  // END CLASS Form1

}
